//
// Created by baigui on 21-9-13.
//

#ifndef SIMPLE_PLAYER_BLOCK_H
#define SIMPLE_PLAYER_BLOCK_H

#include <cstdlib>
#include <cstring>
//#include <cstring>
#include "os/android/thread.h"

/**
 *  包含了三个变量，吧数组分为三部分
 *  0----消费后---start------有用----end---未使用---size
 */
class block_t{
public:
    block_t(int size){
        this->size = size;
        buf = static_cast<uint8_t *>(calloc(size, sizeof(uint8_t)));
    }

    block_t(block_t *block, int need_size){
        size = need_size;
        buf = static_cast<uint8_t *>(calloc(size, sizeof(uint8_t)));

        memcpy( buf, block->buf + block->start,
                block->end - block->start );
        end = block->end - block->start;
    }

    ~block_t(){
        free(buf);
    }

    void reset(){
        end = 0;
        start = 0;
        next = nullptr;
    }
    uint8_t* getbuffer(){
        return buf;
    }

    void setDataSize(int size){
        end = size;
    }

    int getDataSize(){
        return end;
    }

    void setDataStart(int s){
        start = s;
    }

    int getDataStart(){
        return start;
    }

    int getTotalSize(){
        return size;
    }

    block_t* getNext(){
        return next;
    }

    void setNext(block_t * block){
        next = block;
    }

    int64_t i_dts;

private:
    uint8_t* buf;
    int size;
    int end = 0;
    int start = 0;
    block_t *next;

    static block_t* cache_block;
    static sp_mutex_t *p_mutex;
};

class BlockFifo{
public:
    BlockFifo(int size){
        max_size = size;
        sp_mutex_init(&p_mutex);
        sp_mutex_init(&p_block_mutex);
    }

    ~BlockFifo(){
        sp_mutex_lock(&p_mutex);
        block_t* tmp = first;
        while (tmp){
            first = tmp->getNext();
            delete tmp;
        }
        sp_mutex_unlock(&p_mutex);
        sp_mutex_destroy(&p_mutex);

        sp_mutex_destroy(&p_block_mutex);
    }

    void add(block_t * block){
        //防止添加过多元素
        if (size >= max_size) {
            sp_mutex_lock(&p_block_mutex);
        }

        sp_mutex_lock(&p_mutex);
        if (size <= 0){
            first = block;
            last = block;
        } else{
            last->setNext(block);
            last = block;
        }
        size = size + 1;
        sp_mutex_unlock(&p_mutex);
    }

    block_t* popFirst(){

        if (size > max_size){
            sp_mutex_unlock(&p_block_mutex);
        }
        sp_mutex_lock(&p_mutex);
        if(size <= 0)
            return nullptr;
        block_t* tmp = first;
        first = first->getNext();
        if (size == 1)
            last = nullptr;
        size = size - 1;
        sp_mutex_unlock(&p_mutex);
        return tmp;
    }

    block_t* get(){
        if(size <= 0)
            return nullptr;
        return first;
    }

private:
    sp_mutex_t p_mutex;
    sp_mutex_t p_block_mutex;
    block_t* first;
    block_t* last;
    int size = 0;
    int max_size;
};

#endif //SIMPLE_PLAYER_BLOCK_H
